import jwt from 'jsonwebtoken';
import { config } from '../config.js';
import BaseMiddleware from './BaseMiddleware.js';
import ResponseFormatter from '../utils/ResponseFormatter.js';

/**
 * 认证中间件 - 处理JWT令牌验证和用户身份认证
 */
export class AuthenticationMiddleware extends BaseMiddleware {
    constructor(options = {}) {
        super({
            priority: 100, // 高优先级，应该早期执行
            skipPaths: ['/api/auth/login', '/api/auth/register', '/health', '/'], // 跳过认证的路径
            tokenHeader: 'authorization', // 令牌头名称
            tokenPrefix: 'Bearer ', // 令牌前缀
            ...options
        });
    }

    /**
     * 执行认证逻辑
     * @param {Request} req - Express请求对象
     * @param {Response} res - Express响应对象
     * @param {Function} next - Express next函数
     */
    async execute(req, res, next) {
        // 检查是否需要跳过认证
        if (this.shouldSkipAuthentication(req)) {
            return next();
        }

        try {
            // 提取令牌
            const token = this.extractToken(req);
            
            if (!token) {
                throw new Error('No token provided');
            }

            // 验证令牌
            const decoded = await this.verifyToken(token);
            
            // 将用户信息附加到请求对象
            req.user = decoded;
            req.token = token;

            // 记录认证成功
            this.logAuthentication(req, 'SUCCESS');
            
            next();
        } catch (error) {
            this.logAuthentication(req, 'FAILED', error.message);
            return ResponseFormatter.unauthorized(res, this.getErrorMessage(error));
        }
    }

    /**
     * 检查是否应该跳过认证
     * @param {Request} req - Express请求对象
     * @returns {boolean} 是否跳过
     */
    shouldSkipAuthentication(req) {
        const path = req.path;
        const method = req.method;

        // 检查跳过路径
        if (this.options.skipPaths.some(skipPath => {
            if (skipPath.includes('*')) {
                const pattern = skipPath.replace(/\*/g, '.*');
                return new RegExp(`^${pattern}$`).test(path);
            }
            return path === skipPath || path.startsWith(skipPath);
        })) {
            return true;
        }

        // 检查公开的HTTP方法
        if (this.options.publicMethods && this.options.publicMethods.includes(method)) {
            return true;
        }

        // 检查开发环境特殊路径
        if (config.env === 'development' && (path === '/config' || path.startsWith('/docs'))) {
            return true;
        }

        return false;
    }

    /**
     * 从请求中提取令牌
     * @param {Request} req - Express请求对象
     * @returns {string|null} 令牌
     */
    extractToken(req) {
        // 从Authorization头提取
        const authHeader = req.headers[this.options.tokenHeader.toLowerCase()];
        if (authHeader && authHeader.startsWith(this.options.tokenPrefix)) {
            return authHeader.substring(this.options.tokenPrefix.length);
        }

        // 从查询参数提取
        if (req.query.token) {
            return req.query.token;
        }

        // 从Cookie提取
        if (req.cookies && req.cookies.token) {
            return req.cookies.token;
        }

        return null;
    }

    /**
     * 验证JWT令牌
     * @param {string} token - JWT令牌
     * @returns {Promise<Object>} 解码后的用户信息
     */
    async verifyToken(token) {
        try {
            const decoded = jwt.verify(token, config.jwt.secret);
            
            // 检查令牌是否过期
            if (decoded.exp && Date.now() >= decoded.exp * 1000) {
                throw new Error('Token expired');
            }

            // 检查必要字段
            if (!decoded.userId && !decoded.id) {
                throw new Error('Invalid token payload');
            }

            return decoded;
        } catch (error) {
            if (error.name === 'JsonWebTokenError') {
                throw new Error('Invalid token');
            }
            if (error.name === 'TokenExpiredError') {
                throw new Error('Token expired');
            }
            throw error;
        }
    }

    /**
     * 生成JWT令牌
     * @param {Object} payload - 令牌载荷
     * @param {Object} options - 令牌选项
     * @returns {string} JWT令牌
     */
    generateToken(payload, options = {}) {
        const tokenOptions = {
            expiresIn: config.jwt.expiresIn,
            ...options
        };

        return jwt.sign(payload, config.jwt.secret, tokenOptions);
    }

    /**
     * 刷新令牌
     * @param {string} token - 原始令牌
     * @returns {string} 新令牌
     */
    refreshToken(token) {
        try {
            const decoded = jwt.verify(token, config.jwt.secret, { ignoreExpiration: true });
            
            // 移除时间戳字段
            delete decoded.iat;
            delete decoded.exp;
            delete decoded.nbf;

            return this.generateToken(decoded);
        } catch (error) {
            throw new Error('Invalid token for refresh');
        }
    }

    /**
     * 记录认证日志
     * @param {Request} req - Express请求对象
     * @param {string} status - 认证状态
     * @param {string} message - 附加消息
     */
    logAuthentication(req, status, message = '') {
        if (config.log.console) {
            const logData = {
                status,
                method: req.method,
                url: req.originalUrl,
                ip: this.getClientIP(req),
                userAgent: req.get('User-Agent'),
                userId: req.user?.userId || req.user?.id || 'unknown',
                timestamp: new Date().toISOString()
            };

            if (message) {
                logData.message = message;
            }

            console.log(`[AuthenticationMiddleware][${status}]`, logData);
        }
    }

    /**
     * 获取错误消息
     * @param {Error} error - 错误对象
     * @returns {string} 用户友好的错误消息
     */
    getErrorMessage(error) {
        const errorMessages = {
            'No token provided': 'Authentication required',
            'Invalid token': 'Invalid authentication token',
            'Token expired': 'Authentication token has expired',
            'Invalid token payload': 'Invalid authentication token'
        };

        return errorMessages[error.message] || 'Authentication failed';
    }

    /**
     * 创建可选认证中间件（不强制要求认证）
     * @returns {Function} Express中间件函数
     */
    createOptionalMiddleware() {
        return async (req, res, next) => {
            try {
                const token = this.extractToken(req);
                
                if (token) {
                    const decoded = await this.verifyToken(token);
                    req.user = decoded;
                    req.token = token;
                }
            } catch (error) {
                // 可选认证失败时不阻止请求继续
                console.warn(`[AuthenticationMiddleware][OPTIONAL] ${error.message}`);
            }
            
            next();
        };
    }

    /**
     * 创建角色检查中间件
     * @param {string|Array} requiredRoles - 必需的角色
     * @returns {Function} Express中间件函数
     */
    createRoleMiddleware(requiredRoles) {
        const roles = Array.isArray(requiredRoles) ? requiredRoles : [requiredRoles];
        
        return (req, res, next) => {
            if (!req.user) {
                return ResponseFormatter.unauthorized(res, 'Authentication required');
            }

            const userRoles = req.user.roles || [];
            const hasRequiredRole = roles.some(role => userRoles.includes(role));

            if (!hasRequiredRole) {
                return ResponseFormatter.forbidden(res, 'Insufficient permissions');
            }

            next();
        };
    }
}

// 创建默认实例
export const authenticationMiddleware = new AuthenticationMiddleware();

// 导出便捷方法
export const authenticate = () => authenticationMiddleware.getMiddleware();
export const optionalAuth = () => authenticationMiddleware.createOptionalMiddleware();
export const requireRole = (roles) => authenticationMiddleware.createRoleMiddleware(roles);

export default AuthenticationMiddleware;